ko.bindingHandlers.audio = {
    init: function (element, valueAccessor) {
        var viewModel = arguments[3];
        viewModel.Audio(element);
    }
};

ko.bindingHandlers.slider = {
    init: function (element, valueAccessor) {
        var viewModel = arguments[3];
        viewModel.Range(element);
    }
};

$(function () {
    ko.applyBindings(new AudioViewModel());
});

function ParseLyric(text) {
    var reg = /\[\d{2}:\d{2}\.\d{2}\]/g;
    var arr = text.split(reg);
    arr.shift();

    var seconds = [];
    var r = '';
    while (r = reg.exec(text)) {
        seconds.push(r[0]);
    }

    var lyrics = [];
    for (var i in arr) {
        lyrics.push({ sec: TimeToSecond(seconds[i]), text: arr[i] });
    }
    return lyrics;
}

function FindLyric(lyrics, second) {
    var index = -1;

    for (var i in lyrics) {
        var item = lyrics[parseInt(i) + 1];
        if (item && second <= item.sec) {
            index = i;
            break;
        }
    }

    if (index == -1) {
        index = lyrics.length - 1;
    }

    return parseInt(index);
}

function FormatTime(time) {
    var min = parseInt(time / 60);
    var sec = (time - min * 60).toFixed(2);
    if (min < 10) {
        min = '0' + min;
    }
    if (sec < 10) {
        sec = '0' + sec;
    }
    return '[' + min + ':' + sec + ']';
}

function TimeToSecond(time) {
    time = time.substring(1, time.length - 1);
    var array = time.split(':');

    return parseInt(array[0]) * 60 + parseFloat(array[1]);
}

String.prototype.endWith = function (str) {
    var reg = new RegExp(str + "$");
    return reg.test(this);
}

function AudioViewModel() {
    var self = this;

    self.Audio = ko.observable();
    self.Range = ko.observable();
    self.Loop = ko.observable(false);

    self.Start = ko.observable(0);
    self.FormattedStart = ko.computed(function () {
        return FormatTime(self.Start());
    });
    self.End = ko.observable(0);
    self.FormattedEnd = ko.computed(function () {
        return FormatTime(self.End());
    });
    self.Src = ko.observable('');
    self.LyricSrc = ko.observable('');
    self.Url = ko.observable('http://listen.kekenet.com/public.php?la_id=7657');

    self.Lyric = ko.observableArray([]);
    self.CurrentLyric = ko.observableArray([]);
    self.CurrentIndex = ko.observable(-1);

    $(document).bind('keydown', function (event) {
        if (event.keyCode == 119) { //F8
            self.Play();
        }
    });

    self.Loop.subscribe(function (newValue) {
        self.Audio().loop = newValue;
    });

    self.Src.subscribe(function (newValue) {
        self.Audio().src = newValue;

        self.Start(0);
        self.End(0);

        $(self.Audio()).unbind();
        $(self.Audio()).bind('loadedmetadata', function () {
            var duration = self.Audio().duration;
            if (self.End() <= 0) {
                self.Start(0);
                self.End(duration);
            }

            $(self.Range()).slider({
                range: true,
                step: 0.01,
                min: 0,
                max: duration,
                values: [self.Start(), self.End()],
                slide: function (event, ui) {
                    self.Start(ui.values[0]);
                    self.End(ui.values[1]);
                }
            });
        });

        $(self.Audio()).bind('ended', function () {
            if (timer != null) {
                clearTimeout(timer);
            }
        });
    });

    function HtmlEncode(input) {
        var converter = document.createElement("DIV");
        converter.innerText = input;
        var output = converter.innerHTML;
        converter = null;
        return output;
    }

    function unicode(str) {
        return str.replace(/[^\u0000-\u00FF]/g, function ($0) {
            return escape($0).replace(/(%u)(\w{4})/gi, '\\u$2');
        });
    }

    self.LyricSrc.subscribe(function (newValue) {
        jsonrpc.invoke({
            method: 'ajax',
            params: { url: self.LyricSrc(), method: 'GET' },
            success: function (ret) {
                var data = ret.result;
                self.Lyric(ParseLyric(data));
                self.CurrentLyric.removeAll();
                self.CurrentLyric.push.apply(self.CurrentLyric, self.Lyric.slice(0, lineNumber));
            }
        });
    });

    self.Parse = function () {
        jsonrpc.invoke({
            method: 'ajax',
            params: { url: self.Url(), method: 'GET' },
            success: function (ret) {
                console.log(ret);
                var data = ret.result;
                var pattern = /http:\/\/.*?(.mp3|.lrc)/gi;
                var result = data.match(pattern);
                if (result) {
                    for (var i in result) {
                        if (i > 0) {
                            if (result[i].endWith('.mp3') && self.Src() == '') {
                                self.Src(result[i]);
                            } else if (result[i].endWith('.lrc') && self.LyricSrc() == '') {
                                self.LyricSrc(result[i]);
                            }
                        }
                    }
                }
            }
        });

    }

    var lineNumber = 6;
    var timer = null;
    self.Play = function () {
        if (timer != null) {
            clearTimeout(timer);
        }

        self.Audio().load();

        if (self.Lyric().length > 0) {
            timer = setInterval(function () {
                var start = self.Start();
                var end = self.End();

                var time = self.Audio().currentTime;
                var index = FindLyric(self.Lyric(), time);
                var length = self.CurrentLyric().length;

                if (length < (index + lineNumber / 2 + 1)) {
                    self.CurrentLyric.push.apply(self.CurrentLyric, self.Lyric.slice(length, length + lineNumber));
                }

                if (!/^\s+$/g.test(self.Lyric()[index].text)) {
                    self.CurrentIndex(index);
                }

                if (time < start || time > end) {
                    self.Audio().currentTime = start;
                }
            }, 20);
        }

        self.Audio().play();
    }

    self.Pause = function () {
        if (timer != null) {
            clearTimeout(timer);
        }

        self.Audio().pause();
    }
}
